package com.example.locationreport.locationreport.service;

import android.app.Service;
import android.content.Intent;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.text.TextUtils;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.example.locationreport.locationreport.BuildConfig;
import com.example.locationreport.locationreport.CrashApplication;
import com.example.locationreport.locationreport.bean.MQTTAlarmBean;
import com.example.locationreport.locationreport.bean.MQTTTaskBean;
import com.example.locationreport.locationreport.bean.PublishTopicBean;
import com.example.locationreport.locationreport.global.Constant;
import com.example.locationreport.locationreport.global.ConstantInfo;
import com.example.locationreport.locationreport.http.Url;
import com.example.locationreport.locationreport.utils.ACache;
import com.example.locationreport.locationreport.utils.CommonUtils;
import com.example.locationreport.locationreport.utils.JsonUtils;
import com.example.locationreport.locationreport.utils.LogLocationUtils;
import com.example.locationreport.locationreport.utils.LogUtils;

import org.eclipse.paho.android.service.MqttAndroidClient;
import org.eclipse.paho.client.mqttv3.IMqttActionListener;
import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.IMqttToken;
import org.eclipse.paho.client.mqttv3.MqttCallback;
import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttMessage;

import java.util.concurrent.LinkedBlockingDeque;

/**
 * author : King
 * date   : 2023/11/2715:23
 * desc   : 接收服务器发送的消息
 */
public class MqttService extends Service {

    private static final String TAG = MqttService.class.getSimpleName();

    private MqttAndroidClient mMqttAndroidClient;
    private MqttConnectOptions mMqttConnectOptions;

    private String TOPIC_ID = CommonUtils.getImeiID();

    private Thread mThreadHeartbeat;


    /*private Timer mTimerHeartbeat = new Timer();
    private TaskHeartbeat mTaskHeartbeat = null;*/

    /**
     * 定时上传心跳服务
     */
    private Runnable heartbeatRunnable = new Runnable() {
        //    private class TaskHeartbeat extends TimerTask {
        @Override
        public void run() {
            while (true) {
                LogLocationUtils.writeLog(TAG, "运行30秒心跳检测");
                if (mMqttAndroidClient == null || !mMqttAndroidClient.isConnected()) {
                    LogLocationUtils.writeLog(TAG, "连接已断开，重新初始化");
                    initConnection();
                }
                try {
                    Thread.sleep(1000 * 30);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    };

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        LogUtils.e(TAG, "启动服务");
        // 初始化连接
        initConnection();

        // 定时发送心跳任务
        mThreadHeartbeat = new Thread(() -> {
            heartbeatRunnable.run();
        });
        mThreadHeartbeat.setPriority(Thread.MIN_PRIORITY);
        mThreadHeartbeat.setName(Constant.MqttHeartbeatThread);
        mThreadHeartbeat.start();
        /*if(null == mTaskHeartbeat) {
            mTaskHeartbeat = new TaskHeartbeat();
            mTimerHeartbeat.schedule(mTaskHeartbeat , 1000 * 30, 1000 * 30);
        }*/

        // 初始化屏显服务
        return super.onStartCommand(intent, flags, startId);
    }

    /**
     * 初始化mqtt连接
     */
    private void initConnection() {
        //服务器地址（协议+地址+端口号）
        mMqttAndroidClient = new MqttAndroidClient(this, Url.MQTT_URL, MqttClient.generateClientId());
        //设置监听订阅消息的回调
        mMqttAndroidClient.setCallback(mMqttCallback);
        mMqttConnectOptions = new MqttConnectOptions();
        //断开后，是否自动连接
        mMqttConnectOptions.setAutomaticReconnect(true);
        //是否清空客户端的连接记录。若为true，则断开后，broker将自动清除该客户端连接信息
        mMqttConnectOptions.setCleanSession(true);
        //设置超时时间，单位：秒
        mMqttConnectOptions.setConnectionTimeout(10);
        //设置心跳包发送间隔，单位：秒
        mMqttConnectOptions.setKeepAliveInterval(20);
        //设置用户名
        mMqttConnectOptions.setUserName(BuildConfig.MqttUserName);
        //设置密码
        mMqttConnectOptions.setPassword(BuildConfig.MqttPassword.toCharArray());

        // last will message
        boolean doConnect = true;
        String message = JsonUtils.parseBeanToJson(new PublishTopicBean(TOPIC_ID));
        Integer qos = 2;
        Boolean retained = false;

        if (!TextUtils.isEmpty(message) || !TextUtils.isEmpty(TOPIC_ID)) {
            // 最后的遗嘱
            try {
                mMqttConnectOptions.setWill(TOPIC_ID, message.getBytes(), qos.intValue(), retained.booleanValue());
            } catch (Exception e) {
                LogLocationUtils.writeLog(TAG, "Mqtt-initConnection()异常Cause:" + e.getCause() + ";Message:" + e.getMessage());
                doConnect = false;
                iMqttActionListener.onFailure(null, e);
            }
        }

        if (doConnect) {
            doClientConnection();
        }

        LogLocationUtils.writeLog(TAG, "Mqtt连接:" + BuildConfig.MqttUrl + ":" + BuildConfig.MqttSendProt);
        LogLocationUtils.writeLog(TAG, "账号:" + BuildConfig.MqttUserName + ",密码:" + BuildConfig.MqttPassword);
    }

    //订阅主题的回调
    private MqttCallback mMqttCallback = new MqttCallback() {
        @Override
        public void messageArrived(String topic, MqttMessage message) {
            LogLocationUtils.writeLog(TAG, "MQTT接收消息 : " + topic + "..." + message.toString());

            if (TextUtils.isEmpty(topic))
                return;

            if (ConstantInfo.MQTTQueue == null)
                ConstantInfo.MQTTQueue = new LinkedBlockingDeque<>();

            if (topic.contains(Constant.MQTT_Alarm)) {
                // 初始化告警消息
                initAlarmMessage(message.toString());
            } else if (topic.contains(Constant.MQTT_Task)) {
                // 任务消息
                initTaskMessage(message.toString());
            } else if (topic.contains(Constant.MQTT_MaintenanceAlarm)) {
                // 车辆维保告警消息
                initMaintenanceAlarm(message.toString());
            }
        }

        @Override
        public void deliveryComplete(IMqttDeliveryToken arg0) {
            LogLocationUtils.writeLog(TAG, "Mqtt传送完成");
        }

        @Override
        public void connectionLost(Throwable arg0) {
            LogLocationUtils.writeLog(TAG, "Mqtt连接断开:" + arg0.getCause() + ";Message:" + arg0.getMessage());
            //连接断开，重连
            delayedRun(3);
        }
    };

    /**
     * 初始化告警消息
     *
     * @param message
     */
    private void initAlarmMessage(String message) {
        MQTTAlarmBean mqttAlarmBean = JsonUtils.parseJsonToBean(message, MQTTAlarmBean.class);

        // 消息告警状态
        if (!mqttAlarmBean.isAlarmStatus()) {
            LogLocationUtils.writeLog(TAG, "不进行播报,消息状态为无需播报 : 消息ID:" + mqttAlarmBean.getUuid() + ",消息内容:" + mqttAlarmBean.getVoiceMessage());
            return;
        }

        // 消息在十秒钟内有重复接收
        if (!TextUtils.isEmpty(ACache.get(CrashApplication.getContext()).getAsString(mqttAlarmBean.getUuid()))) {
            LogLocationUtils.writeLog(TAG, "不进行播报,消息在十秒钟内有重复接收 : 消息ID:" + mqttAlarmBean.getUuid() + ",消息内容:" + mqttAlarmBean.getVoiceMessage());
            return;
        }

        // 缓存消息,缓存时效为10秒
        if (!TextUtils.isEmpty(mqttAlarmBean.getVoiceMessage()))
            ACache.get(CrashApplication.getContext()).put(mqttAlarmBean.getUuid(), mqttAlarmBean.getVoiceMessage(), 10);

        if (mqttAlarmBean.getRuleTypeId() > 0 && mqttAlarmBean.getRuleTypeId() < 7) {
            LogLocationUtils.writeLog(TAG, "进行播报,消息缓存十秒 : 消息ID:" + mqttAlarmBean.getUuid() + ",消息内容:" + mqttAlarmBean.getVoiceMessage());
            // 将消息存储到缓存队列中
            try {
                if (mqttAlarmBean.getRuleTypeId() == 2) {
                    ConstantInfo.MQTTQueue.putFirst(mqttAlarmBean.getVoiceMessage());
                } else {
                    ConstantInfo.MQTTQueue.putLast(mqttAlarmBean.getVoiceMessage());
                }
                sendSpeakReceiver(0);
            } catch (InterruptedException e) {
                LogLocationUtils.writeLog(TAG, "告警消息存储异常,消息类型:" + mqttAlarmBean.getRuleTypeId() + "Cause:" + e.getCause() + ",Message:" + e.getMessage());
                e.printStackTrace();
            }
        }
    }

    /**
     * 初始化任务消息
     */
    private void initTaskMessage(String message) {
        MQTTTaskBean mqttTaskBean = JsonUtils.parseJsonToBean(message, MQTTTaskBean.class);

        if (mqttTaskBean != null && !TextUtils.isEmpty(mqttTaskBean.getMessage())) {
            try {
                ConstantInfo.MQTTQueue.putLast(mqttTaskBean.getMessage());
                sendSpeakReceiver(1);
            } catch (InterruptedException e) {
                LogLocationUtils.writeLog(TAG, "任务消息存储异常,Cause:" + e.getCause() + ",Message:" + e.getMessage());
                e.printStackTrace();
            }
        }
    }

    /**
     * 初始车辆维保告警消息
     */
    private void initMaintenanceAlarm(String message) {
        if (TextUtils.isEmpty(message))
            return;

        try {
            ConstantInfo.MQTTQueue.putLast(message);
            sendSpeakReceiver(1);
        } catch (InterruptedException e) {
            LogLocationUtils.writeLog(TAG, "车辆维保告警消息,Cause:" + e.getCause() + ",Message:" + e.getMessage());
            e.printStackTrace();
        }
    }

    /**
     * 发送播放语音广播
     *
     * @param type
     */
    private Intent mSpeakReceiverIntent;

    private void sendSpeakReceiver(int type) {
        if (ConstantInfo.IsMQTTSpeaking
                || ConstantInfo.MQTTQueue == null
                || ConstantInfo.MQTTQueue.size() < 1)
            return;

        if (mSpeakReceiverIntent == null)
            mSpeakReceiverIntent = new Intent(Constant.ReceiverSpeak);
        mSpeakReceiverIntent.putExtra(Constant.TYPE, type);
        sendBroadcast(mSpeakReceiverIntent);
    }

    /**
     * 连接MQTT服务器
     */
    private void doClientConnection() {
        LogLocationUtils.writeLog(TAG, "Mqtt连接是否建立:" + mMqttAndroidClient.isConnected());

        if (mMqttAndroidClient != null && CommonUtils.isConnectIsNormal()) {
            if (!mMqttAndroidClient.isConnected()) {
                try {
                    /**
                     * options：用来携带连接服务器的一系列参数，例如用户名、密码等
                     * userContext：可选对象，用于向回调传递上下文。一般传null即可
                     * callback：用来监听MQTT是否连接成功的回调
                     */
                    mMqttAndroidClient.connect(mMqttConnectOptions, null, iMqttActionListener);
                } catch (Exception e) {
                    LogLocationUtils.writeLog(TAG, "Mqtt连接出错 : " + "cause : " + e.getCause() + "message : " + e.getMessage());
                }
            }
        } else {
            LogLocationUtils.writeLog(TAG, "Mqtt连接失败 : " + "Client是否为空?" + (mMqttAndroidClient == null) + ",网络是否正常?" + CommonUtils.isConnectIsNormal());
            delayedRun(2);
        }
    }

    /**
     * MQTT是否连接成功的监听
     */
    private IMqttActionListener iMqttActionListener = new IMqttActionListener() {
        @Override
        public void onSuccess(IMqttToken arg0) {
            LogLocationUtils.writeLog(TAG, "MQTT连接成功");
            try {
                //成功连接以后开始订阅
                //订阅主题，参数：主题、服务质量
                mMqttAndroidClient.subscribe(TOPIC_ID + "/+", 2);
            } catch (MqttException e) {
                LogLocationUtils.writeLog(TAG, "Mqtt-listener中订阅主题失败异常Cause:" + e.getCause() + ";Message:" + e.getMessage());
            }
        }

        @Override
        public void onFailure(IMqttToken arg0, Throwable arg1) {
            LogLocationUtils.writeLog(TAG, "Mqtt连接失败:" + arg1.getMessage() + "arg0?" + (arg0 == null));
            arg1.printStackTrace();

            delayedRun(1);
        }
    };

    /**
     * 延迟执行
     *
     * @param what
     */
    private void delayedRun(int what) {
        try {
            //连接失败，重连（可关闭服务器进行模拟）
            if (CommonUtils.isConnectIsNormal()) {
                delayedHandler.sendEmptyMessageDelayed(what, 5000);
            } else {
                try {
                    Thread.sleep(1000 * 3);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                Thread networkCheck = new Thread(() -> {
                    delayedRun(0);
                });
                networkCheck.setPriority(Thread.MIN_PRIORITY);
                networkCheck.start();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private Handler delayedHandler = new Handler() {
        @Override
        public void handleMessage(@NonNull Message msg) {
            LogLocationUtils.writeLog(TAG, "Mqtt连接失败,延时执行重连操作" + msg.what);
            doClientConnection();
        }
    };

    @Override
    public void onDestroy() {
        /*if(mTimerHeartbeat != null){
            mTimerHeartbeat.cancel();
            mTimerHeartbeat = null;
        }

        if(mTaskHeartbeat != null){
            mTaskHeartbeat.cancel();
            mTaskHeartbeat = null;
        }*/

        try {
            if (mThreadHeartbeat != null)
                mThreadHeartbeat.interrupt();
        } catch (Exception e) {
            e.printStackTrace();
        }

        super.onDestroy();
    }
}
